package com.mornstar.common.utils;

import org.springframework.lang.NonNull;
import org.springframework.lang.Nullable;

import java.math.BigDecimal;

/**
 * Miscellaneous utility methods for number conversion and parsing.
 * <p>Mainly for internal use within the framework; consider Apache's
 * Commons Lang for a more comprehensive suite of number utilities.
 *
 * @author xiek
 * @since 1.1.2
 */
public class NumberUtil {
    /**
     * The default int value used
     */
    private static final Integer DEFAULT_INT_VAL = 0;

    /**
     * The default float value used
     */
    private static final Float DEFAULT_FLOAT_VAL = 0.00f;

    /**
     * The default double value used
     */
    private static final Double DEFAULT_DOUBLE_VAL = 0.00d;

    /**
     * The default 浮点型小数位数
     */
    private static final Integer DEFAULT_DOUBLE_SACLE = 2;

    /**
     * 判断字符串是否为整数类型
     **/
    public static boolean isInteger(String str) {
        try {
            Integer.parseInt(str);
        } catch (NumberFormatException e) {
            return false;
        }
        return true;
    }

    /**
     * 判断字符串是否为浮点类型
     **/
    public static boolean isDouble(String str) {
        try {
            Double.parseDouble(str);
        } catch (NumberFormatException e) {
            return false;
        }
        return true;
    }

    public static int getIntegerValue(final Object str) {
        return NumberUtil.getIntegerValue(String.valueOf(str));
    }

    /**
     * 将字符串转换成Integer类型，如果转换失败则返回 0
     *
     * @return double
     **/
    public static Integer getIntegerValue(String str) {
        return getIntegerValue(str, DEFAULT_INT_VAL);
    }

    /**
     * 将字符串转换成Integer类型，如果转换失败则返回 0
     *
     * @return double
     **/
    public static Integer getIntegerValue(String str, @NonNull Integer tar) {
        try {
            return Integer.parseInt(str);
        } catch (NumberFormatException e) {
            return tar;
        }
    }

    /**
     * 将字符串转换成float类型，如果转换失败则返回 0
     *
     * @return double
     **/
    public static Float getFloatValue(Object value) {
        return getFloatValue(String.valueOf(value));
    }

    /**
     * 将字符串转换成float类型，如果转换失败则返回 0
     *
     * @return double
     **/
    public static Float getFloatValue(String str) {
        return getFloatValue(str, DEFAULT_FLOAT_VAL);
    }

    /**
     * 将字符串转换成Integer类型，如果转换失败则返回 0
     *
     * @return double
     **/
    public static Float getFloatValue(String str, @NonNull Float tar) {
        try {
            return Float.parseFloat(str);
        } catch (NumberFormatException e) {
            return tar;
        }
    }

    /**
     * 将字符串转换成double类型，如果转换失败则返回 0.00
     *
     * @return double
     **/
    public static Double getDoubleValue(Object value) {
        return getDoubleValue(String.valueOf(value));
    }

    /**
     * 将字符串转换成double类型，如果转换失败则返回 0.00
     *
     * @return double
     **/
    public static double getDoubleValue(String str) {
        return getDoubleValue(str, DEFAULT_DOUBLE_VAL);
    }

    /**
     * 将字符串转换成double类型，如果转换失败则返回默认值
     **/
    public static double getDoubleValue(String str, @NonNull Double tar) {
        try {
            return Double.parseDouble(str);
        } catch (NumberFormatException e) {
            return tar;
        }
    }

    /**
     * 将字符串转换成double类型，并保留两位小数
     *
     * @return double
     **/
    public static double getDoubleRound(String str) {
        return getDoubleRound(str, DEFAULT_DOUBLE_SACLE);
    }

    /**
     * 将字符串转换成double类型，并保留指定位数小数/四舍五入
     *
     * @param str   目标字符串
     * @param sacle 小数点范围
     * @return double
     **/
    public static double getDoubleRound(String str, @NonNull Integer sacle) {
        if (!isDouble(str)) {
            return DEFAULT_DOUBLE_VAL;
        }

        BigDecimal bigdecimal = new BigDecimal(str);
        return bigdecimal.setScale(sacle, BigDecimal.ROUND_HALF_UP).doubleValue();
    }

    /**
     * 对double类型数据进行四舍五入
     *
     * @return double
     **/
    public static double getDoubleRound(double dou) {
        return getDoubleRound(dou, DEFAULT_DOUBLE_SACLE);
    }

    /**
     * 对double类型数据进行四舍五入，并保留指定位数小数/四舍五入
     *
     * @param dou   目标数据
     * @param sacle 小数范围
     * @return double
     **/
    public static double getDoubleRound(double dou, @NonNull Integer sacle) {
        BigDecimal bigdecimal = new BigDecimal(dou);

        return bigdecimal.setScale(sacle, BigDecimal.ROUND_HALF_UP).doubleValue();
    }

    /**
     * 将字符串转换成Long类型
     * <code>zero</code> if the conversion fails.</p>
     *
     * <p>If the string is <code>null</code>, <code>zero</code> is returned.</p>
     *
     * <pre>
     *   NumberUtil.toLong(null) = 0L
     *   NumberUtil.toLong("")   = 0L
     *   NumberUtil.toLong("1")  = 1L
     * </pre>
     *
     * @param str the string to convert, may be null
     * @return the long represented by the string, or <code>0</code> if
     * conversion fails
     */
    public static long getLongValue(final Object str) {
        return getLongValue(String.valueOf(str));
    }

    /**
     * 将字符串转换成Long类型
     * <code>zero</code> if the conversion fails.</p>
     *
     * <p>If the string is <code>null</code>, <code>zero</code> is returned.</p>
     *
     * <pre>
     *   NumberUtil.toLong(null) = 0L
     *   NumberUtil.toLong("")   = 0L
     *   NumberUtil.toLong("1")  = 1L
     * </pre>
     *
     * @param str the string to convert, may be null
     * @return the long represented by the string, or <code>0</code> if
     * conversion fails
     */
    public static long getLongValue(final String str) {
        return getLongValue(str, 0L);
    }

    /**
     * <p>Convert a <code>String</code> to a <code>long</code>, returning a
     * default value if the conversion fails.</p>
     *
     * <p>If the string is <code>null</code>, the default value is returned.</p>
     *
     * <pre>
     *   NumberUtil.toLong(null, 1L) = 1L
     *   NumberUtil.toLong("", 1L)   = 1L
     *   NumberUtil.toLong("1", 0L)  = 1L
     * </pre>
     *
     * @param str          the string to convert, may be null
     * @param defaultValue the default value
     * @return the long represented by the string, or the default if conversion fails
     */
    public static long getLongValue(@Nullable final String str, final long defaultValue) {
        if (str == null) {
            return defaultValue;
        }
        try {
            return Long.valueOf(str);
        } catch (final NumberFormatException nfe) {
            return defaultValue;
        }
    }
}
